#include <eq/configEvent.h>
#include <eq/layout.h>
#include <eq/server.h>
#include <eq/view.h>

#include "config.h"

eqApp::Config::Config(eq::ServerPtr parent):
eq::Config(parent),
state(),
width(),
height(),
z0(),
w0(),
h0(),
leftDown(),
rightDown()
{
}

bool eqApp::Config::init(const eq::uint128_t&)
{
    this->registerObject(&state);
    state.commit();
    if(!eq::Config::init(state.getID()))
        return false;
    eq::Wall const& wall = this->getLayouts().at(0)->getViews().at(0)->getWall();
    z0 = (wall.topLeft.z() + wall.bottomRight.z()) / 2;
    w0 = wall.getWidth();
    h0 = wall.getHeight();
    return true;
}

bool eqApp::Config::exit()
{
    if(!eq::Config::exit())
        return false;
    this->deregisterObject(&state);
    return true;
}

uint32_t eqApp::Config::startFrame(const eq::uint128_t&)
{
    return eq::Config::startFrame(state.getVersion());
}

bool eqApp::Config::handleEvent(const eq::ConfigEvent* event)
{
    uint32_t const Left = 1, Right = 4;
    switch(event->data.type)
    {
        case eq::Event::WINDOW_POINTER_BUTTON_PRESS:
            switch(event->data.pointerButtonPress.button)
            {
                case Left:
                    leftDown = true;
                    break;
                case Right:
                    rightDown = true;
                    break;
                default:
                    break;
            }
            return false;
            break;
        case eq::Event::WINDOW_POINTER_BUTTON_RELEASE:
            switch(event->data.pointerButtonRelease.button)
            {
                case Left:
                    leftDown = false;
                    break;
                case Right:
                    rightDown = false;
                    break;
                default:
                    break;
            }
            return false;
            break;
        case eq::Event::WINDOW_POINTER_MOTION:
            if(leftDown)
                state.addRotate(event->data.pointerMotion.dy, event->data.pointerMotion.dx);
            if(rightDown)
            {
                GLfloat z  = state.position.z;
                GLfloat dx = event->data.pointerMotion.dx * z * w0 / (z0 * width);
                GLfloat dy = event->data.pointerMotion.dy * z * h0 / (z0 * height);
                state.relativeMove(dx, -dy, 0);
            }
            if(leftDown || rightDown)
                state.commit();
            return leftDown || rightDown;
            break;
        case eq::Event::WINDOW_POINTER_WHEEL:
            state.scale *= std::pow(1.25, event->data.pointerWheel.xAxis);
            state.commit();
            return true;
            break;
        case eq::Event::WINDOW_RESIZE:
            width  = event->data.resize.w;
            height = event->data.resize.h;
            return true;
            break;
        case eq::Event::VIEW_RESIZE:
        {
            eq::Config::handleEvent(event);
            eq::Wall const& wall = this->getLayouts().at(0)->getViews().at(0)->getWall();
            z0 = (wall.topLeft.z() + wall.bottomRight.z()) / 2;
            w0 = wall.getWidth();
            h0 = wall.getHeight();
        }
            return true;
            break;
        default:
            return eq::Config::handleEvent(event);
    }
}
